﻿using Basic.WxApiRemoteModel;
using Basic.WxApiRemoteModel.WxBind.Model;
using Basic.WxApiService.Interface;
using Basic.WxApiService.WxModel.Platform;
using Basic.WxCollect;
using Basic.WxLocalEvent;
using Basic.WxModel.PlatformBind;
using Basic.WxRemoteModel.WxBind.Model;
using Basic.WxService.Interface;
using Basic.WxService.Model.WxBind;
using WeDonekRpc.Client.Attr;
using WeDonekRpc.Helper;
using WeDonekRpc.Model;

namespace Basic.WxService.lmpl
{
    [ClassLifetimeAttr(ClassLifetimeType.SingleInstance)]
    internal class WxBindService : IWxBindService
    {
        private readonly IWxBindStateService _BindState;
        private readonly IWxPlatformService _Platform;
        private readonly IWxPlatformBindCollect _PlatformBind;
        private readonly IWxMerTokenService _MerToken;

        public WxBindService (IWxBindStateService bindState,
            IWxPlatformService platform,
            IWxPlatformBindCollect platformBind,
            IWxMerTokenService merToken)
        {
            this._BindState = bindState;
            this._Platform = platform;
            this._PlatformBind = platformBind;
            this._MerToken = merToken;
        }
        public BindStatus GetState (string applyId)
        {
            WxMerBindCache apply = this._BindState.Get(applyId);
            return new BindStatus
            {
                Status = apply.BindStatus,
                WxAppId = apply.WxAppId
            };
        }
        public string GetCallbackUri (string applyId)
        {
            WxMerBindCache apply = this._BindState.Get(applyId);
            return apply.GetCallbackUri();
        }
        public string ApplyBind (ApplyBindArg obj, MsgSource source)
        {
            return this._BindState.ApplyBind(obj, source);
        }
        public ApplyCodeResult GetPreAuthCode (string applyId)
        {
            WxMerBindCache apply = this._BindState.Get(applyId);
            if (apply.CheckState(WxBindStatus.初始化))
            {
                apply.PreauthCode = this._Platform.GetPreauthCode(applyId, out int expire);
                apply.OverTime = DateTime.Now.AddSeconds(expire - 2);
                apply.BindStatus = WxBindStatus.待绑定;
                this._BindState.Save(apply);
            }
            return new ApplyCodeResult
            {
                AuthType = apply.AuthType,
                ApplyId = applyId,
                ComponentAppId = apply.AppId,
                PreAuthCode = apply.PreauthCode
            };
        }
        public void Begin (WxMerBind obj)
        {
            WxMerBindCache task = this._BindState.Begin(obj.PreAuthCode, obj.WxAppId);
            try
            {
                this._BindPlatform(obj.PlatformAppId, obj.WxCode);
                this._BindState.Complete(task);
            }
            catch (ErrorException e)
            {
                if (task != null)
                {
                    this._BindState.Fail(task, e.ErrorCode);
                }
                throw;
            }
            finally
            {
                new WxMerBindEvent
                {
                    WxAppId = obj.WxAppId,
                    PlatformAppId = obj.PlatformAppId
                }.Public("Bind");
            }
        }
        private void _BindPlatform (string appId, string code)
        {
            WxAuthorization auth = this._Platform.GetMerAuth(appId, code);
            this._MerToken.SetToken(auth, appId);
            WxPlatformBindAdd add = new WxPlatformBindAdd
            {
                WxAppId = auth.authorizer_appid,
                AppId = appId,
                RefreshToken = auth.authorizer_refresh_token,
                WxPrower = auth.func_info.ConvertAll(c => (WxPrower)c.funcscope_category.id)
            };
            this._PlatformBind.Sync(add);
        }
    }
}
